package com.stock.core.service.stock;

import com.alibaba.fastjson.JSON;
import com.stock.api.domain.stock.StockCodeBean;
import com.stock.api.domain.stock.StockHistoryBean;
import com.stock.api.service.stock.StockCodeService;
import com.stock.api.service.stock.StockHistoryService;
import com.stock.api.util.StockUtils;
import com.stock.comm.util.DateUtil;
import com.stock.core.persistence.reader.stock.StockCodeReaderMapper;
import com.stock.core.persistence.writer.stock.StockHistoryWriterMapper;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * <p>类说明</p>
 *
 * @author 张峰 zfvip_it@163.com
 * @createTime: 2016/9/13 17:00
 */
@Service("stockHistoryService")
public class StockHistoryServiceImpl implements StockHistoryService {


    private static final Logger LOGGER = LoggerFactory.getLogger(StockCodeServiceImpl.class);

    @Resource
    private StockHistoryWriterMapper stockHistoryWriterMapper;

    @Resource
    private StockCodeReaderMapper stockCodeReaderMapper;

    @Resource
    private StockCodeService stockCodeService;

    /**
     * 创建线程池
     */
    ExecutorService pool = null;

    /**
     * 更新股票历史数据
     */
    public int extactStockHistoryData(String stockDate) throws Exception {
        LOGGER.debug("开始更新股票成交数据");
        try {

            if (StringUtils.isBlank(stockDate))
                stockDate = DateUtil.getTxnDateStr(new Date());
            /**得到所有股票代码列表*/
            List<StockCodeBean> stockCodeList = stockCodeReaderMapper.queryAll();

            if (stockCodeList == null || stockCodeList.size() == 0) {
                LOGGER.info("没有需要更新成交数据的股票！");
                return 0;
            }
            int size = stockCodeList.size();
            pool = Executors.newFixedThreadPool(size > 100 ? 100 : size);
            //更新历史数据状态
            stockHistoryWriterMapper.updateStatus(stockDate, null);

            List<Future> rowResult = new CopyOnWriteArrayList<Future>();
            for (final StockCodeBean stockCodeBean : stockCodeList) {

                final String finalStockDate = stockDate;
                rowResult.add(pool.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            /**抓取股票历史数据*/
                            StockHistoryData stockHistoryData = getStockHistoryData(stockCodeBean, finalStockDate);
                            if (stockHistoryData != null) {
                                /**转换历史数据*/
                                StockHistoryBean stockHistoryBean = getStockHistory(stockHistoryData);
                                if (stockHistoryBean != null) {
                                    stockHistoryBean.setStockCode(stockCodeBean.getStockCode());
                                    stockHistoryWriterMapper.insertSelective(stockHistoryBean);
                                }
                            } else {
                                LOGGER.error("抓取股票：" + stockCodeBean.getStockCode() + "成交数据失败！");
                            }
                        } catch (Exception e) {
                            LOGGER.error("抓取股票：" + stockCodeBean.getStockCode() + "成交数据失败！", e);
                        }
                    }
                }));
            }
            //等待处理结果
            for (Future f : rowResult) {
                f.get();
            }
            //启动一次顺序关闭，执行以前提交的任务，但不接受新任务。如果已经关闭，则调用没有其他作用
            pool.shutdown();

        } catch (Exception e) {
            LOGGER.error("更新股票成交数据失败", e);
            throw new Exception("更新股票成交数据失败", e);
        }
        LOGGER.info("更新股票成交数据完成");
        return 0;
    }

    /**
     * 根据股票代码获取历史数据
     *
     * @param stockCodeBean
     * @param finalStockDate
     * @return
     */
    public StockHistoryData getStockHistoryData(StockCodeBean stockCodeBean, String finalStockDate) {
        /**开始查询日期*/
        String start_date = finalStockDate;
        /**截止查询日期*/
        String end_date = start_date;
        /**查询股票代码*/
        String stockCode = stockCodeBean.getStockCode();
        /**API接口*/
        String url = getUrl(stockCode, start_date, end_date);
        /**得到结果*/
        String historySearch = stockCodeService.getHtmlContent(url);
        LOGGER.debug(url);
        /**转换数据*/
        if (historySearch != null && historySearch.length() > 90) {
            historySearch = historySearch.replaceFirst("historySearchHandler\\(\\[", "");
            historySearch = historySearch.substring(0, historySearch.length() - 2);
            StockHistoryData stockHistoryData = JSON.parseObject(historySearch, StockHistoryData.class);
            stockHistoryData.setStockCode(stockCode);
            return stockHistoryData;
        }
        return null;
    }

    /**
     * 转换数据
     *
     * @param stockHistoryData
     */
    private StockHistoryBean getStockHistory(StockHistoryData stockHistoryData) {
        StockHistoryBean stockHistoryBean = new StockHistoryBean();
        if (stockHistoryData != null && stockHistoryData.getHq().length > 0) {
            Object[][] obj = stockHistoryData.getHq();
            /**股票代码*/
            stockHistoryBean.setStockCode(stockHistoryData.getStockCode());
            /**日期*/
            stockHistoryBean.setStockDate(obj[0][0].toString());
            /**开盘价*/
            stockHistoryBean.setOpenPrice(new BigDecimal(obj[0][1].toString()));
            /**收盘价*/
            stockHistoryBean.setClosePrice(new BigDecimal(obj[0][2].toString()));
            /**涨跌额*/
            stockHistoryBean.setUpsandDowns(new BigDecimal(obj[0][3].toString()));
            /**涨跌幅*/
            stockHistoryBean.setChangeRate(new BigDecimal(obj[0][4].toString().replace("%", "")));
            /**最低价*/
            stockHistoryBean.setLowestAmnout(new BigDecimal(obj[0][5].toString()));
            /**最高价*/
            stockHistoryBean.setHighestAmount(new BigDecimal(obj[0][6].toString()));
            /**成交量*/
            stockHistoryBean.setStockVolume(new BigDecimal(obj[0][7].toString()));
            /**总成交额*/
            stockHistoryBean.setTotalTurnover(new BigDecimal(obj[0][8].toString()));
            /**换手率*/
            if (obj[0][9].toString().indexOf("-") < 0)
                stockHistoryBean.setTurnoverRate(new BigDecimal(obj[0][9].toString().replace("%", "")));
            else
                stockHistoryBean.setTurnoverRate(new BigDecimal(0));
            /**状态*/
            stockHistoryBean.setStatus("00");
            /**创建时间*/
            stockHistoryBean.setCreateTime(new Date());
        }
        return stockHistoryBean;
    }

    /**
     * 更新股票实时数据,只能更新当天数据
     *
     * @throws Exception
     */
    public int extactStockRealTimeData() throws Exception {
        LOGGER.debug("开始更新股票成交数据");
        /**得到所有股票代码列表*/
        int records = 0;
        List<StockCodeBean> stockCodeList = stockCodeReaderMapper.queryAll();
        if (stockCodeList != null && stockCodeList.size() > 0) {
            //更新历史数据状态
            stockHistoryWriterMapper.updateStatus(DateUtil.formatCurrentDate(), null);
            //批量保存
            stockHistoryWriterMapper.batchInsert(StockUtils.getStockHistoryData(stockCodeList));
        } else {
            LOGGER.info("没有需要更新成交数据的股票！");
            records = 0;
        }

        LOGGER.info("更新股票成交数据完成");
        return records;
    }

    /***
     * 根据日期和股票代码更新收盘数据
     *
     * @param date
     * @param stockCode
     */
    public void extactStockHistoryData(String date, String stockCode) {
        //获取收盘数据
        StockHistoryBean stockHistoryBean = getStockHistoryData(date, stockCode);
        if (stockHistoryBean != null) {
            //更新历史数据状态
            stockHistoryWriterMapper.updateStatus(stockHistoryBean.getStockDate(), stockCode);
            stockHistoryWriterMapper.insert(stockHistoryBean);
        }
    }

    /***
     * 根据股票代码和日期获取收盘数据
     *
     * @param date
     * @param stock_code
     * @return
     */
    public StockHistoryBean getStockHistoryData(String date, String stock_code) {
        StockCodeBean stockCodeBean = new StockCodeBean();
        stockCodeBean.setStockCode(stock_code);
        try {
            /**抓取股票历史数据*/
            StockHistoryData stockHistoryData = getStockHistoryData(stockCodeBean, date);
            if (stockHistoryData != null) {
                /**转换历史数据*/
                return getStockHistory(stockHistoryData);

            } else {
                LOGGER.debug("抓取股票：" + stockCodeBean.getStockCode() + "成交数据失败！");
            }
        } catch (Exception e) {
            LOGGER.error("抓取股票：" + stockCodeBean.getStockCode() + "成交数据失败！", e);
        }
        return null;
    }

    /**
     * 网页地址
     *
     * @return
     */
    public String getUrl(String stockCode, String start_date, String end_date) {
        //http://hq.sinajs.cn/list=sh601006,sh600010
        return "http://q.stock.sohu.com/hisHq?code=cn_" + stockCode + "&start=" + start_date + "&end=" + end_date + "&stat=1&order=D&period=d&callback=historySearchHandler&rt=jsonp";
    }

    /**
     * 网页返回历史数据对象
     */
    public static class StockHistoryData implements Serializable {

        /**
         * 状态
         */
        private Integer status;
        /**
         * 历史数据
         */
        private Object[][] hq;
        /**
         * 代码
         */
        private String stockCode;
        /**
         * 汇总
         */
        private Object[] stat;

        public StockHistoryData() {
        }

        public Object[][] getHq() {
            return hq;
        }

        public void setHq(Object[][] hq) {
            this.hq = hq;
        }

        public Object[] getStat() {
            return stat;
        }

        public void setStat(Object[] stat) {
            this.stat = stat;
        }

        public Integer getStatus() {
            return status;
        }

        public void setStatus(Integer status) {
            this.status = status;
        }

        public String getStockCode() {
            return stockCode;
        }

        public void setStockCode(String stockCode) {
            this.stockCode = stockCode;
        }
    }

}
